package org.rainbowinverted.charging.device.connect.bl.server.encode;

import cn.hutool.core.util.HexUtil;
import com.dix.codec.bkv.BKV;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageEncoder;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.rainbowinverted.charging.common.core.StringPadUtils;
import org.rainbowinverted.charging.device.connect.bl.server.handler.BlAbstractHandler;
import org.rainbowinverted.charging.device.connect.bl.server.handler.BlHandlerFactory;
import org.rainbowinverted.charging.device.connect.bl.server.constants.BlConstants;
import org.rainbowinverted.charging.device.connect.bl.server.message.out.BlDeviceMessageOut;
import org.rainbowinverted.charging.device.connect.bl.server.util.BlOpCodeMap;
import org.rainbowinverted.charging.device.connect.bl.server.util.SerialNumberGenerator;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Objects;

/**
 * 柏来bkv编码器处理程序
 *
 * @author huaiping
 */
@Slf4j
@Component
@ChannelHandler.Sharable
public class BlBkvEncoder extends MessageToMessageEncoder<BlDeviceMessageOut> {
    @Resource
    private BlHandlerFactory blHandlerFactory;

    @Override
    protected void encode(ChannelHandlerContext channelHandlerContext, BlDeviceMessageOut message, List<Object> list) throws Exception {
        BKV bkv = new BKV();
        // 功能码
        String opCode = StringPadUtils.leftPad(Integer.toHexString(
                BlOpCodeMap.convertOpCodeToDeviceCode(message.getMessageType())), "0", 2);
        bkv.add(0x01, HexUtil.decodeHex(opCode));
        // 序列号
        if (Objects.isNull(message.getFrameSerialNo())) {
            message.setFrameSerialNo(SerialNumberGenerator.nextSerialNumber());
        }
        String serialNumber = StringPadUtils.leftPad(Long.toHexString(message.getFrameSerialNo()), "0", 16);
        bkv.add(0x02, HexUtil.decodeHex(serialNumber));
        // 设备号
        bkv.add(0x03, HexUtil.decodeHex(message.getDeviceNo().toString()));
        // 业务数据编码
        BlAbstractHandler<?, BlDeviceMessageOut> blHandler = blHandlerFactory.getHandler(message.getMessageType());
        if (Objects.isNull(blHandler)) {
            log.error("没有找到匹配的handler，opCode: {}", message.getMessageType());
            return;
        }
        blHandler.write(message, bkv);
        // bkv 编码
        byte[] bytes = bkv.pack();
        StringBuilder buffer = new StringBuilder(BlConstants.START_SYMBOL_BL);
        // 包长（帧长 + 校验位）
        buffer.append(StringPadUtils.leftPad(Integer.toHexString(bytes.length + 3), "0", 4));
        // BKV数据
        buffer.append(HexUtil.encodeHexStr(bytes));
        // 校验和
        buffer.append(checkSum(bytes));
        // 包尾
        buffer.append(BlConstants.END_SYMBOL_BL);
        // 写数据
        String writeData = buffer.toString();
        log.info("send message, opCode: {}, hex: {}", opCode, writeData);
        ByteBuf byteBuf = channelHandlerContext.alloc().buffer();
        byteBuf.writeBytes(HexUtil.decodeHex(writeData));
        list.add(byteBuf);
    }

    /**
     * 校验和
     *
     * @param data   数据
     * @return {@link String}
     */
    public static String checkSum(byte[] data) {
        int sum = 0;
        for (byte b : data) {
            sum += (b & 0xFF);
        }
        return String.format("%02x", sum);
    }
}
